/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package elaborate.vwbe.impl;

import elaborate.vwbe.dom.DocumentEX;
import elaborate.vwbe.impl.resource_fetcher.HttpClientFactory;
import elaborate.vwbe.resource_fetcher.HttpAuthenticationScheme;
import elaborate.vwbe.resource_fetcher.ResourceFetcher;
import elaborate.vwbe.resource_fetcher.ResourceFetcherCallback;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.w3c.dom.Document;
import org.w3c.tidy.Tidy;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 *
 * @author lendle
 */
public class DefaultResourceFetcher implements ResourceFetcher {
    private ResourceFetcherCallback callback=null;
    public Document fetchDOMResource(URL url, String charset) throws IOException {
        try {
            //use JTidy to fix not well-formed HTML
            Tidy tidy = new Tidy();
            tidy.setXHTML(true);
            tidy.setForceOutput(true);
            
            InputStream input=this.openInputStream(url);
            try {
                InputStreamReader reader = new InputStreamReader(input, "utf-8");
                StringWriter output = new StringWriter();
                tidy.parse(reader, output);
                String docString = output.toString();
                //System.out.println("docString="+docString);
                //set Xerces features to avoid DTD-validation error
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                dbf.setNamespaceAware(true);
                dbf.setFeature("http://xml.org/sax/features/namespaces", true);
                dbf.setFeature("http://xml.org/sax/features/validation", false);
                dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
                dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
                dbf.setValidating(false);
                dbf.setExpandEntityReferences(false);
                DocumentBuilder docBuilder = dbf.newDocumentBuilder();
                Document doc = new DocumentEX(docBuilder.parse(new InputSource(new StringReader(docString))));
                return doc;
            } catch (Exception e) {
                Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, e.getMessage());
            } finally {
                input.close();
            }
            return null;
        } catch (Exception ex) {
            Logger.getLogger(DefaultResourceFetcher.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    public String fetchStringResource(URL url, String charset) throws IOException {
        InputStream input = url.openStream();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(input, "utf-8"));
            StringBuilder buffer=new StringBuilder();
            String str=reader.readLine();
            while(str!=null){
                if(buffer.length()>0){
                    buffer.append("\r\n");
                }
                buffer.append(str);
                str=reader.readLine();
            }
            return buffer.toString();
        } catch (Exception e) {
            Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, e.getMessage());
        } finally {
            input.close();
        }
        return null;
    }

    public void setResourceFetcherCallback(ResourceFetcherCallback callback) {
        this.callback=callback;
    }

    protected InputStream openInputStream(URL url) throws IOException, MalformedURLException, NoSuchAlgorithmException, KeyManagementException, UnsupportedEncodingException, FileNotFoundException, ParserConfigurationException, SAXException, XPathExpressionException{
        String protocol=url.getProtocol().toLowerCase();
        if(protocol.equals("http") || protocol.equals("https")){
            HttpClient httpClient = HttpClientFactory.createHttpClient(url, (callback!=null)?callback:new ResourceFetcherCallback(){

                public String getUserName() {
                    return null;
                }

                public String getPassword() {
                    return null;
                }

                public HttpAuthenticationScheme getHttpAuthenticationScheme() {
                    return HttpAuthenticationScheme.Basic;
                }
            });
            HttpGet httpget = new HttpGet(url.toString());
            HttpResponse response = httpClient.execute(httpget);

            //InputStream input = url.openStream();
            InputStream input=response.getEntity().getContent();
            return input;
        }
        else{
            return url.openStream();
        }
    }
}
